import bufferOverlay from "@/components/LayerTool/modules/buffer-overlay.vue";
import { createApp, h } from "vue";
// 计算折线长度的函数
function toolFormatLength(line) {
  // 默认 EPSG:3857
  let length = ol.sphere.getLength(line, {
    projection: 'EPSG:4326'
  });
  let output;
  if (length > 1000) {
    output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km';
  } else {
    output = Math.round(length * 100) / 100 + ' ' + 'm';
  }
  return output;
};
// 格式化距离
function toolFormatDistance(dis) {
  if (dis > 1000) {
    return Math.round((dis / 1000) * 100) / 100 + ' ' + 'km';
  } else {
    return Math.round(dis * 100) / 100 + ' ' + 'm';
  }
};
let pointermoveFunc = null;
function MeasureDuanmianHor({ map, mittBus }) {
  const ins = MeasureDuanmianHor.getIns();
  if (ins) {
    return ins
  }
  this.map = map;
  this.mittBus = mittBus;
  this.calcIng = false;
  this.draw = null;
  this.sketch = null;
  this.helpMsg = '';
  this.measureTooltip = null;
  this.helpText = null;
  this.layerLine = null;
  this.layerPoint = null;
  this.overlaysArr = [];
  // 绘制过程中的折线样式
  this.styleLineNormal = new ol.style.Style({
    stroke: new ol.style.Stroke({
      color: 'rgba(255, 87, 34, 0.8)',
      lineDash: [5, 10],
      width: 2
    })
  });
  // 绘制结束后的折线样式
  this.styleLineHighlight = new ol.style.Style({
    stroke: new ol.style.Stroke({
      color: 'rgba(255, 87, 34, 1)',
      lineDash: null,
      width: 3
    })
  });
  this.overlayForLocate = {
    overlay: null,
    app: null,
    size: true,
    detail: true
  };
  this.init();
  MeasureDuanmianHor.ins = this;
}
MeasureDuanmianHor.getIns = function () {
  return MeasureDuanmianHor.ins;
}
MeasureDuanmianHor.create = function ({ map, mittBus }) {
  return new MeasureDuanmianHor({ map, mittBus })
}
// 初始化
MeasureDuanmianHor.prototype.init = function () {
  if (!ol) { return }
  if (!this.map) { return }
  // 矢量图层源
  this.drawSourceLine = new ol.source.Vector();
  this.layerLine = new ol.layer.Vector({
    source: this.drawSourceLine
  });
  this.layerLine.setZIndex(20);
  this.map.addLayer(this.layerLine);

  this.layerPoint = new ol.layer.Vector({
    source: this.drawSourceLine,
    style: new ol.style.Style({
      image: new ol.style.Circle({
        radius: 6,
        fill: new ol.style.Fill({
          color: '#ffffff'
        }),
        stroke: new ol.style.Stroke({
          color: '#fd5723',
          width: 3
        })
      }),
    })
  });
  this.layerPoint.setZIndex(21);
  this.map.addLayer(this.layerPoint);
  // 初始化绑定事件
  this.bindEvt();
  // 初始化提示文本的overlay
  this.initHelpOverlay();
}
MeasureDuanmianHor.prototype.pointermoveFunc = function (evt) {
  // 在拖拽过程中或者未开启测量，不处理
  if (evt.dragging || this.calcIng === false) {
    return;
  }
  // 绘制第一个点前的提示信息
  this.helpMsg = '点击鼠标左键，确定起始点位';
  if (this.sketch) {
    // 确定了第一个点之后的提示信息
    this.helpMsg = '移动鼠标，点击左键确定下一点位，鼠标右键结束测量';
  }
  this.helpText.innerHTML = this.helpMsg;
  // 设置提示信息的位置
  this.helpTooltip.setPosition(evt.coordinate);
}
MeasureDuanmianHor.prototype.unbindEvt = function () {
  this.map.getViewport().style.cursor = 'inherit';
  this.map.un('pointermove', pointermoveFunc);
  pointermoveFunc = null;
}
MeasureDuanmianHor.prototype.bindEvt = function () {
  this.map.getViewport().style.cursor = 'pointer';
  // 鼠标移动，动态设置提示信息的位置
  pointermoveFunc = this.pointermoveFunc.bind(this)
  // 鼠标移动，动态设置提示信息的位置
  this.map.on('pointermove', pointermoveFunc);
}
MeasureDuanmianHor.prototype.setOverlayForLocate = function ({ coordinate, listData }) {
  if (this.overlayForLocate.overlay) {
    this.overlayForLocate.overlay.setPosition(coordinate);
  }
  const attrIns = this;
  const unid = new Date().getTime();
  const app = createApp({
    render() {
      return h(bufferOverlay, {
        unid,
        mainTitle: "详细信息",
        propsType: "green",
        listData,
        onlyLocate: false,
        size: attrIns.overlayForLocate.size,
        detail: attrIns.overlayForLocate.detail,
        unid,
        onClose: (e) => {
        },
        onSize: (e) => {
          attrIns.overlayForLocate.size = e;
        },
        onDetail: (e) => {
          attrIns.overlayForLocate.detail = e;
        },
      });
    }
  });

  const parent = document.createElement('div');
  const el = app.mount(parent).$el;

  if (this.overlayForLocate.app) {
    this.overlayForLocate.app.unmount();
    this.overlayForLocate.overlay.setElement(el);
    this.overlayForLocate.app = app;
    return
  }

  // 创建Overlay
  const overlay = new ol.Overlay({
    id: unid,
    element: el,
    offset: [0, -45],
    positioning: 'bottom-center',
    insertFirst: false,
    stopEvent: true
  });
  this.map.addOverlay(overlay);
  overlay.setPosition(coordinate);
  this.overlayForLocate.overlay = overlay;
  this.overlayForLocate.app = app;
}
MeasureDuanmianHor.prototype.initHelpOverlay = function () {
  let helpText = document.querySelector('#helpTxt');
  if (!helpText) {
    helpText = document.createElement('div');
    helpText.setAttribute('id', 'helpTxt');
  }
  this.helpText = helpText;
  this.helpTooltip = new ol.Overlay({
    element: helpText,
    offset: [15, 0],
    positioning: 'center-left'
  });
  this.map.addOverlay(this.helpTooltip);
}
MeasureDuanmianHor.prototype.handleClickCalcDistance = function () {
  if (this.calcIng) {
    // 结束测量
    this.calcIng = false;
    this.map.removeInteraction(this.draw);
    this.helpTooltip.getElement().style.display = 'none';
  } else {
    // 开始测量，初始化交互
    this.calcIng = true;
    this.initInteraction();
  }
}
MeasureDuanmianHor.prototype.createMeasureTooltip = function () {
  const measureTooltipElement = document.createElement('div');
  measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure';
  this.measureTooltip = new ol.Overlay({
    element: measureTooltipElement,
    offset: [0, -15],
    positioning: 'bottom-center',
    stopEvent: false,
    // insertFirst属性控制Overlay是否应该被插入到地图元素列表的开头
    insertFirst: false
  });
  this.map.addOverlay(this.measureTooltip);
  this.overlaysArr.push(this.measureTooltip);
}
MeasureDuanmianHor.prototype.putOverlayToLine = function (coordinate, text) {
  // const div = document.createElement('div');
  // div.className = 'ol-tooltip ol-tooltip-measure';
  // div.innerHTML = text;
  // // 创建Overlay
  // const overlay = new ol.Overlay({
  //   element: div,
  //   offset: [0, -15],
  //   positioning: 'bottom-center',
  //   stopEvent: false
  // });
  // this.overlaysArr.push(overlay);
  // this.map.addOverlay(overlay); // 将Overlay添加到地图
  // overlay.setPosition(coordinate); // 设置Overlay的位置

  const feature = new ol.Feature({
    geometry: new ol.geom.Point(coordinate)
  });
  this.layerPoint.getSource().addFeature(feature);
}
// 清空 overlays
MeasureDuanmianHor.prototype.removeOverlays = function () {
  if (!this.overlaysArr.length) { return }
  this.overlaysArr.forEach(v => {
    this.map.removeOverlay(v);
  })
}
// 添加交互
MeasureDuanmianHor.prototype.initInteraction = function () {
  // 创建绘制折线的交互控件
  this.draw = new ol.interaction.Draw({
    source: this.drawSourceLine,
    type: 'LineString',
    style: this.styleLineNormal
  });
  // 将交互添加到地图
  this.map.addInteraction(this.draw);
  let listener; // 监听geomerty的change事件，开始时候绑定，结束时候解绑
  this.draw.on('drawstart', (evt) => {
    let lines = {}; // 每段折线的线集合
    this.createMeasureTooltip(); // 创建一个overlay，用于实时显示距离，测量结束后停留在折线末端
    this.helpTooltip.getElement().style.display = 'block'; // 展示提示信息
    this.sketch = evt.feature;
    let tooltipCoord = evt.coordinate;
    // 绑定Geometry发生变化事件，实时显示距离和设置位置
    let tagHead = false;
    listener = this.sketch.getGeometry().on('change', (evt) => {
      // 展示总距离
      const geom = evt.target;
      let output = toolFormatLength(geom); // 计算距离
      tooltipCoord = geom.getLastCoordinate(); // 折线的最后一个点的坐标
      //this.measureTooltip.getElement().innerHTML = '总长' + output; // 显示计算后的距离
      //this.measureTooltip.setPosition(tooltipCoord); // 设置overlay位置显示在折线的末端
      // 展示分段距离
      const coordinates = geom.getCoordinates().slice(0, -1);
      // 获取折线的每段线段 给除了最后一段线段增加距离显示
      for (let i = 0; i < coordinates.length; i++) {
        const start = coordinates[i]; // 折线起点
        const end = coordinates[i + 1]; // 折线终点
        if (!tagHead) {
          tagHead = true;
          this.putOverlayToLine(start, '起点')
        }
        if (!end) {
          continue;
        }
        // 使用开始可结束的经纬度组成唯一标识
        const key = 'l_' + start.join('_').replace(/[.]/g, '') + '-' + end.join('_').replace(/[.]/g, '');
        if (!lines[key] && tooltipCoord.join('') != end.join('')) {
          lines[key] = true;
          const start4326 = start//ol.proj.transform(start, 'EPSG:3857', 'EPSG:4326');
          const end4326 = end//ol.proj.transform(end, 'EPSG:3857', 'EPSG:4326')
          const distance = ol.sphere.getDistance(start4326, end4326); // 计算距离
          tagHead && this.putOverlayToLine(end, toolFormatDistance(distance)); // 添加overlay显示折线距离
        }
      }
    });
  });
  this.draw.on('drawend', (evt) => {
    // 显示距离的div设置类名
    this.measureTooltip.getElement().className = 'ol-tooltip ol-tooltip-static';
    this.measureTooltip.setOffset([0, -7]);
    evt.feature.setStyle(this.styleLineHighlight); // 设置折线样式
    ol.Observable.unByKey(listener); // 解绑change事件
    this.sketch = null;
    this.measureTooltip = null;

    this.mittBus && this.mittBus.emit('line', {
      geometry: evt.feature.getGeometry().getCoordinates(),
      isFresh: true
    })
  });
}
// 清除响应
MeasureDuanmianHor.prototype.clear = function () {
  // 结束测量
  this.calcIng = false;
  this.map.removeInteraction(this.draw);
  this.helpTooltip.getElement().style.display = 'none';
  this.unbindEvt();
}
MeasureDuanmianHor.prototype.clearLocateOverlay = function() {
  if(this.overlayForLocate.overlay) {
    this.map.removeOverlay(this.overlayForLocate.overlay);
    this.overlayForLocate.overlay = null;
  }
  if(this.overlayForLocate.app) {
    this.overlayForLocate.app.unmount();
    this.overlayForLocate.app = null;
  }
}
// 销毁：销毁响应 + 删除图层
// 销毁
MeasureDuanmianHor.prototype.destroy = function () {
  this.clear();
  this.map.removeLayer(this.layerPoint);
  this.map.removeLayer(this.layerLine);
  this.removeOverlays();
  this.clearLocateOverlay();
  this.mittBus && this.mittBus.all.clear();
  MeasureDuanmianHor.ins = null;
}
export default MeasureDuanmianHor